package cn.mw.cmdb.view;

import cn.hutool.core.bean.PropDesc;
import cn.hutool.extra.spring.SpringUtil;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.param.FunctionModuleEnum;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.CustomModelServiceImpl;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.InstanceInfoUtil;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.util.ListMapObjUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.ListOrderedMap;

import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.InstanceInfo.SearchPrefix;
import static cn.mw.cmdb.entity.PropertyInfo.allPropertyMap;
import static cn.mw.cmdb.param.FunctionModuleEnum.enableMonitor;
import static cn.mw.cmdb.processor.MonitorValue.FunctionModule;
import static cn.mw.cmdb.processor.MonitorValue.modelIdKey;
import static cn.mw.cmdb.service.impl.InstanceViewImpl.financeParentId;
import static cn.mw.cmdb.util.CMDBTool.getFieldInfoToMap;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;
import static cn.mw.cmdb.view.InstanceListViewConverter.dataListMap;
import static cn.mw.cmdb.view.InstanceListViewConverter.propertyListMapKey;

public class InstanceInfoAuthViewConverter implements ViewConvert<Object, Object> {
    private Set<String> authFieldNames;
    private static final String managePropertyCatolog = "纳管属性";
    private static final String mw_contextParamKey = "contextParam";
    private static final String mwValKey = "val";

    private List<InstanceInpuFieldsView> ret;
    private Map<String, List<PropertyInfo>> modelAllPropertyList;

    private Map<String, ModelInfo> modelId2FinanceParentModelInfoMap;

    private List<String> financeParentModelIds;

    private List<String> ignoreCheckList = Arrays.asList(PropertyTypeQRCode.ID);


    private InstanceInfoUtil instanceInfoUtil;

    @Override
    public void init(ViewConvertContext convertContext) throws Exception {
        FieldViewAuthType fieldViewAuthType = (FieldViewAuthType) convertContext.get(ViewConvertContext.FieldViewAuthTypeKey);
        instanceInfoUtil = SpringUtil.getBean(InstanceInfoUtil.class);
        CmdbServiceManage cmdbServiceManage = SpringUtil.getBean(CmdbServiceManage.class);
        if (fieldViewAuthType == FieldViewAuthType.list) {
            InstanceServiceImpl service = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            String modelIdKey = CMDBTool.getFieldName(InstanceInfo::getModelId);
            String modelId = convertContext.get(modelIdKey).toString();
            List<PropertyInfo> propertyInfos = (List) service.getFields(modelId, FieldViewAuthType.list);
            authFieldNames = new HashSet<>();
            for (PropertyInfo propertyInfo : propertyInfos) {
                authFieldNames.add(propertyInfo.getName());
            }
        }
        if (fieldViewAuthType == FieldViewAuthType.look) {
            ret = (List<InstanceInpuFieldsView>) convertContext.get(InstanceInpuFieldsView.Key);
            ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
            modelAllPropertyList = propertyService.getModelAllPropertyList(new ArrayList<>(), null);
            CustomModelServiceImpl service = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
            ModelSearchParam modelSearchParam = new ModelSearchParam();
            modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
            List<ModelInfo> financeParentModelInfos = service.getAllModelByParentGroup(modelSearchParam);
            modelId2FinanceParentModelInfoMap = financeParentModelInfos.stream().collect(Collectors.toMap(ModelInfo::getId, item -> item, (o1, o2) -> o1));
            financeParentModelIds = financeParentModelInfos.stream().map(ModelInfo::getId).toList();
        }
        if (fieldViewAuthType == FieldViewAuthType.upd) {
            Object paramData = convertContext.getParamData();
            if (paramData instanceof InstanceInfo) {
                String modelId = ((InstanceInfo) paramData).getModelId();
                CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
                ModelInfo modelInfo = new ModelInfo();
                modelInfo.setId(modelId);
                ModelInfo modelInfos = modelService.doSelectById(modelInfo);
                Map<String, PropertyInfo> propertyInfo = modelInfos.getPropertyInfoById();
                //获取当前模型的所有属性
                convertContext.put(allPropertyMap, propertyInfo);
            }
        }
    }

    @Override
    public Object convert(Object instanceInfo, ViewConvertContext context) throws Exception {
        Map<String, Object> data = new HashMap<>();
        if (instanceInfo != null && instanceInfo instanceof InstanceInfo) {
            data = getFieldInfoToMap(instanceInfo, Arrays.asList(CMDBTool.getFieldName(InstanceInfo::getData)));
            data.putAll(((InstanceInfo) instanceInfo).getData());
        }
        if (instanceInfo != null && instanceInfo instanceof Map) {
            data = (Map) instanceInfo;
        }
        Map map = new ListOrderedMap();

        String modelId = strValueConvert(data.get(modelIdKey));
        String financePId = strValueConvert(data.get(financeParentId));
        List<String> keys = new ArrayList<>(data.keySet());
        //默认升序
        instanceInfoUtil.orderInstanceInfoKeyList(keys);

        FieldViewAuthType fieldViewAuthType = (FieldViewAuthType) context.get(ViewConvertContext.FieldViewAuthTypeKey);
        if (fieldViewAuthType == FieldViewAuthType.list) {

            if (null != data && null != authFieldNames) {
                for (String key : keys) {
                    if (authFieldNames.contains(key)) {
                        map.put(key, data.get(key));
                    }
                }
            }
        } else if (fieldViewAuthType == FieldViewAuthType.look) {
            if (CollectionUtils.isNotEmpty(ret)) {
                List<Map> mapList = new ArrayList<>();
                List<InstanceInpuFieldsView> newRet = new ArrayList<>();
                //没有功能模块字段和运维管理权限的，不展示纳管属性
                if (data.get(FunctionModule) == null || !((List) data.get(FunctionModule)).contains(enableMonitor.getCode())) {
                    newRet = ret.stream().filter(s -> s.getType() != null && !managePropertyCatolog.equals(s.getType())).collect(Collectors.toList());
                } else {
                    newRet = ret;
                }
                //获取当前模型属性
                List<PropertyInfo> propertyInfoList = modelAllPropertyList.get(modelId);
                CmdbServiceManage cmdbServiceManage = SpringUtil.getBean(CmdbServiceManage.class);
                InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
                instanceService.filterFinanceParentModelProperty(propertyInfoList, modelId2FinanceParentModelInfoMap.get(financePId), financeParentModelIds);
                for (InstanceInpuFieldsView fieldsView : newRet) {
                    List<InstanceInputFieldView> dataFieldInfo = fieldsView.getData();
                    for (InstanceInputFieldView instanceInpuFieldView : dataFieldInfo) {
                        if (data != null && (ignoreCheckList.contains(instanceInpuFieldView.getPropertyType()) || data.containsKey(instanceInpuFieldView.getId()))) {
                            Object obj = instanceInpuFieldView.getValue(data);
                            String typeId = instanceInpuFieldView.getPropertyType();
                            Map<String, Object> contextParam = instanceInpuFieldView.getContext();
                            if (contextParam != null) {
                                contextParam.put(dataListMap, data);
                                contextParam.put(propertyListMapKey, propertyInfoList);
                            }
                            PropertyType propertyType = PropertyTypeManage.getPropertyType(typeId);
                            Object val = propertyType.lookValue(obj, contextParam);
                            instanceInpuFieldView.setValue(val);
                        }
                    }
                    Map m = ListMapObjUtils.beanToMap(fieldsView);
                    mapList.add(m);
                }
                return mapList;
            }
        } else {
            Map<String, PropertyInfo> allPropertyMapMap = (Map<String, PropertyInfo>) context.get(allPropertyMap);
            CMDBTool.visitCMDBAnnotion(InstanceInfo.class, new Consumer<PropDesc>() {
                @Override
                public void accept(PropDesc propDesc) {
                    String fieldName = propDesc.getFieldName();
                    Method getMethod = propDesc.getGetter();
                    try {
                        if (!SearchPrefix.equals(fieldName)) {//去除data中的数据
                            Object value = getMethod.invoke(instanceInfo);
                            map.put(fieldName, value);
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            for (String key : keys) {//将data中的数据直接放到map中
                Object object = data.get(key);
                if (allPropertyMapMap != null && allPropertyMapMap.containsKey(key)) {
                    PropertyInfo propertyInfo = allPropertyMapMap.get(key);
                    String typeId = propertyInfo.getPropertyTypeRef().getTypeId();
                    PropertyType propertyType = PropertyTypeManage.getPropertyType(typeId);
                    Map<String, Object> contextParam = propertyInfo.getPropertyTypeRef().getContext();
                    if (contextParam == null) {
                        contextParam = new HashMap<>();
                        contextParam.put(dataListMap, data);
                    }
                    object = propertyType.selValue(object, contextParam);
                }
                map.put(key, object);
            }
        }
        return map;
    }
}
